/**
 * @description: 信用卡服务端
 * @create 2024/3/7 3:36
 * @writer 颜善民
 */

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.gson.Gson;

public class CardServer {
    private static final ExecutorService SERVER_EXECUTOR = Executors.newFixedThreadPool(10); // 设置线程池大小为10个线程
    private static final String DATA_FILE = "cards.dat"; // 保存到服务端本地文件名
    private Map<String, Double> cardBalances; // 保存卡号和余额的map

    public CardServer() {
        cardBalances = loadCardBalances(); // 初始化map
    }

    public static void main(String[] args) {
        CardServer server = new CardServer();
        server.startServer();
    }

    /**
     * 启动服务
     */
    private void startServer() {
        try (
                // 1 建立服务端Socket
                // 1.1 创建ServerSocket对象，监听端口4444
                ServerSocket serverSocket = new ServerSocket(4444)) {
            while (true) {
                try {
                    final Socket client = serverSocket.accept();// 使用accept()阻塞等待客户请求，有客户请求
                    // 到来则产生一个Socket对象
                    // 创建线程池线程处理客户请求，lambda表达式
                    SERVER_EXECUTOR.execute(() -> handleClient(client));
                } catch (IOException e) {
                    System.out.println("接受请求失败: " + e.getMessage());
                }
            }
        } catch (IOException e) {
            System.out.println("ServerSocket 初始化失败: " + e.getMessage());
        }
    }

    /**
     * 处理请求
     * @param client 客户端socket
     */
    private void handleClient(Socket client) {
        // 2 处理Client请求
        // 2.1 获取客户端ip前缀
        String clientAddress = client.getInetAddress().getHostAddress();
        // 2.2 输出客户端连接状态
        System.out.println(clientAddress + " 已连接");
        // 2.3 读取客户端输入
        try (BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
             PrintWriter out = new PrintWriter(client.getOutputStream(), true)) {
            String inputLine;
            Gson gson = new Gson();
            while ((inputLine = in.readLine()) != null) {
                // 2.4 使用Gson解析json数据，将json数据保存到封装的transaction中
                Transaction transaction = gson.fromJson(inputLine, Transaction.class);
                // 2.5 进行充值消费业务处理
                String response = processTransaction(transaction);
                // 2.6 将处理结果保存到服务器本地文件
                saveCardBalances();
                // 2.7 将处理结果返回给客户端
                out.println(response); // 发送响应到客户端
            }
        } catch (IOException e) {
            System.out.println(clientAddress + " 处理过程中发生错误: " + e.getMessage());
        } finally {
            // 2.8 关闭连接
            System.out.println(clientAddress + " 已断开");
        }
    }

    /**
     * 处理充值消费业务逻辑
     * @param transaction 交易信息
     * @return responseMessage 处理结果
     */
    private String processTransaction(Transaction transaction) {
        // 3.1 卡号不存在，创建并初始化余额为0
        cardBalances.putIfAbsent(transaction.cardNumber, 0.0);
        // 3.2 卡号存在，获取余额到balance变量
        double balance = cardBalances.get(transaction.cardNumber);

        String responseMessage;
        // 3.3 根据交易类型进行处理
        // 3.3.1 消费
        if ("消费".equals(transaction.type)) {
            if (balance >= transaction.amount) {
                // 3.3.1.1 余额足，扣除map中的余额
                cardBalances.put(transaction.cardNumber, balance - transaction.amount);
                responseMessage = "消费成功，当前余额：" + (balance - transaction.amount);
            } else {
                // 3.3.1.2 余额不足，提示余额不足
                responseMessage = "消费失败，余额不足";
            }
        }
        // 3.3.2 充值
        else if ("充值".equals(transaction.type)) {
            // 3.3.2.1 余额足，增加map中的余额
            cardBalances.put(transaction.cardNumber, balance + transaction.amount);
            responseMessage = "充值成功，当前余额：" + (balance + transaction.amount);
        } else {
            responseMessage = "操作失败，无效的操作类型";
        }
        // 服务端信息记录
        System.out.println("卡号 " + transaction.cardNumber + " 操作: " + transaction.type + "，金额: " + transaction.amount + "。" + responseMessage);
        return responseMessage;
    }

    /**
     * 加载本地文件中的卡号和余额信息
     * @return 卡号和余额的map
     */
    private Map<String, Double> loadCardBalances() {
        File file = new File(DATA_FILE);
        if (file.exists()) {
            try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
                return (Map<String, Double>) ois.readObject();
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return new HashMap<>();
    }
    /**
     * 保存卡号和余额到本地文件
     */
    private void saveCardBalances() {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(DATA_FILE))) {
            oos.writeObject(cardBalances);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 交易信息
     */
    static class Transaction {
        String type; // 消费或充值 交易类型
        String cardNumber; // 卡号
        double amount; // 金额
    }
}
